from navigator.html.tags import all_tags, Html

from sgmllib import SGMLParser

class Parser(SGMLParser):
    """
    The Parser works with the tags described in html/tags.py

    Each tag has an attribute called attrs, it's a list of html attributes
    that are relevant (we want to keep) for that tag (e.g. href for <a>).

    >>> p = Parser("<html><body><a href="http://google.com/"></a></body></html>")
    >>> p.html.children
    [<Body>]
    >>> p.html.children[0].children
    [<A>]
    >>> print p.html.children[0].children[0].href
    http://google.com/
    """
    def __init__(self, string, verbose=0):
        SGMLParser.__init__(self, verbose)
        self.html = self.atag = None
        self.feed(string)
        self.close()

    def handle_data(self, data):
        if self.atag:
            self.atag.text = data

    def __getattr__(self, attr):
        """
        It may look a little ugly but it works and it's not that bad.

        SGMLParser calls the method start_<tag> when it finds <tag> and 
        the method end_<tag> when it finds </tag>. We use the information 
        provided by each Tag object to build generic start_ and end_ methods in
        runtime.
        """
        if attr in self.__dict__:
            return self.__dict__[attr]

        if attr.startswith("start_"):
            tag = attr.split("_")[-1]
            if tag in all_tags:
                cls = all_tags[tag]
                
                def start_(attrs):
                    # start_<tag> method
                    tag = cls(self.atag)
                    if self.atag:
                        self.atag.children.append(tag)
                   
                    for attr,value in attrs:
                        if attr in cls.attrs:
                            tag.__dict__[attr] = value
                    
                    if isinstance(tag, Html):
                        self.html = tag
                    self.atag = tag
                
                return start_
        
        if attr.startswith("end_"):
            if attr.split("_")[-1] in all_tags:
                def end_():
                    # end_<tag> method
                    self.atag = self.atag.parent
                return end_
        
        raise AttributeError

def _test():
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    _test()

